﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace AAA.Schedule
{
    public class ScheduleManager
    {        
        private List<ITask> _lstRunAtOnce;
        private List<ITask> _lstPeriod;
        private List<ITask> _lstHasRun;
        private bool _isStarted;
        private int _iTimerInterval = 100;
        private Thread _tSchedule;

        public ScheduleManager()
        {
            _lstRunAtOnce = new List<ITask>();
            _lstPeriod = new List<ITask>();
        }

        public void ExecuteOneTimeTask()
        {
            try
            {
                _lstHasRun = new List<ITask>();
                foreach (ITask task in _lstRunAtOnce)
                {
                    _lstHasRun.Add(task);
                    task.Execute(null);                    
                }
                _lstRunAtOnce = new List<ITask>();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void InitialSchedule()
        {
            DateTime dtNow = DateTime.Now;
            DateTime dtNextTime;
            try
            {
                ExecuteOneTimeTask();
                foreach (ITask task in _lstPeriod)
                {
                    try
                    {
                        if (task.StartTime.Ticks > dtNow.Ticks)
                        {
                            task.NextExecuteTime = task.StartTime;
                            continue;
                        }

                        if (task.ExecuteAtStart)
                            task.Execute(null);

                        dtNextTime = task.StartTime;
/*
                        while ((dtNextTime = dtNextTime.AddSeconds(task.Interval / 1000.0)).Ticks < dtNow.Ticks) 
                            ;
 */ 
                        task.NextExecuteTime = dtNextTime;
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public int TimerInterval
        {
            get { return _iTimerInterval; }
            set { _iTimerInterval = value; }
        }

        public void Start()
        {
            InitialSchedule();
            _tSchedule = new Thread(new ThreadStart(ExecuteSchedule));
            _tSchedule.Start();
            _isStarted = true;
        }

        public void Stop()
        {
            if(_tSchedule != null)
                _tSchedule.Abort();
            _isStarted = false;
        }

        public bool IsStarted
        {
            get { return _isStarted; }
        }

        private void ExecuteSchedule()
        {
            while (_isStarted)
            {
                long lNow = DateTime.Now.Ticks;
                List<ITask> lstNeedToRemove = new List<ITask>();
                foreach (ITask task in _lstPeriod)
                {
                    try
                    {
                        if (task == null)
                            continue;

                        if (lNow > task.EndTime.Ticks)
                        {
                            lstNeedToRemove.Add(task);
                            continue;
                        }
                        if ((lNow > task.NextExecuteTime.Ticks) && (task.CompletedTime.CompareTo(task.NextExecuteTime) <= 0))
                        {
                            task.TaskStatus = TaskStatusEnum.InProcess;
                            task.Execute(null);
                            task.CompletedTime = DateTime.Now;
                            task.TaskStatus = TaskStatusEnum.Completed;                      
                            while(task.NextExecuteTime.Ticks < lNow)
                                task.NextExecuteTime = task.NextExecuteTime.AddSeconds(task.Interval / 1000.0);
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message + "," + ex.StackTrace);
                        throw ex;
                    }
                }

                foreach (ITask task in lstNeedToRemove)
                    _lstPeriod.Remove(task);

                Thread.Sleep(TimerInterval);
            }
        }

        public void AddTask(ITask task)
        {
            switch (task.TaskType)
            {
                case TaskTypeEnum.Once:
                    _lstRunAtOnce.Add(task);
                    break;

                case TaskTypeEnum.Period:
                    _lstPeriod.Add(task);
                    break;
            }
        }
    }
}
